# -*- coding: utf-8 -*-
import cv2
import numpy as np
import time
import requests
import base64
import os
import re
import pandas as pd
import json
#加载配置
with open("./config.json","r") as f :
    config = json.load(f)
class SaveCsv:
    def save_csv(self,data, save_path, name):
        """
        保存数据为csv格式并保存到save_path
        :param data:      字典数据
        :param save_path: 保存的路径，到文件,注意后缀.xlsx
        :param name:      再单元格添加的名字
        :return:
        """
        if not data :
            print("传入save_csv的data为空")
            return None
        # 处理数据
        for val, key in zip(data.values(), data.keys()):
            num_list = self.to_num(val)
            result = [" " for x in range(1, 14)]
            for j in range(len(num_list)):
                result[int(num_list[j]) - 1] = name
            data[key] = result

        # 如果存在则追加
        if os.path.exists(save_path):
            current_df = pd.read_excel(save_path)
            current_data = current_df.to_dict(orient='list')
            # 防止添加额外的索引
            del current_data["Unnamed: 0"]
            # 合并两个字典
            self.merge_dict(current_data, data)
            data_processed = current_data
        else:
            data_processed = data
        # 保存data到csv
        df = pd.DataFrame(self.sort_weekday(data_processed), index=[f"第{i}节" for i in range(1, 14)])
        output_file = save_path  # 输出文件名
        df.to_excel(output_file, engine="openpyxl")
    def merge_dict(self,dict1: dict, dict2: dict):
        for key in dict1.keys():
            for i in range(len(dict1[key])):
                try:
                    if dict1[key][int(i)] != " ":
                        dict1[key][int(i)] += ","
                    dict1[key][int(i)] += dict2[key][int(i)]
                except (ValueError,KeyError):
                    print("dict1",dict1)
                    print("dict2",dict2)
                    print("key:", key, "-某个不存在")
    def to_num(self,array):
        result = []
        for i in array:
            for j in re.findall("\d{0,2}", i):
                if j:
                    result.append(j)
        return result
    def sort_weekday(self,data:dict) :
        return {"周一": data["周一"],"周二": data["周二"],"周三": data["周三"],"周四": data["周四"],"周五": data["周五"],"周六": data["周六"]}
class Process_json_to_txt:
    def analyse_json(self,json_data_list):
        """
        :param json_data_list: 一个包含json数据的列表
        :return:返回一个列表，元素是字符串，每个字符串是解析的一json元素
        """
        string_result = []
        # 将json数据添加到string中
        for json_item in json_data_list :
            string = ""
            for item in json_item["words_result"]:
                string += item["words"]
            string_result.append(string)
        return string_result
class Process_txt_to_csv:
    def process_txt_to_csv(self,txt):
        return self.analysed_data_to_dict(self.analyse_data(txt))
    def analyse_data(self,txt_data_list):
        """
        将每一条文本都处理成一个列表包含在一个大列表下 ：例:[['13-13', '周一'], ['11-12', '周一']]
        :param txt_data_list: 文本列表
        :return: result
        """
        result = []
        for txt_item in txt_data_list:
            class_time = re.findall("(\d*-\d*)节", txt_item.strip())
            if class_time:
                weekday = re.findall("周.?", txt_item)
                if weekday:
                    class_time.append(weekday[0])
                    result.append(class_time)
                else:
                    result.append(class_time)
                    print("未识别出周数：" + class_time.strip())
            else:
                print("识别失败:" + class_time.strip())
        # print(result)
        return result
    def analysed_data_to_dict(self,analysed_data):
        dict_result = {}
        for item in analysed_data :
            if type(item) == list:
                if len(item) >= 2:
                    try:
                        dict_result[item[-1]].append(item[0])
                    except KeyError:
                        dict_result[item[-1]] = []
                        dict_result[item[-1]].append(item[0])
        return dict_result
class Ocr_images:
    def ocr_image(self,image):
        """
        :param image: opencv的image对象
        :return: 所有图片的json,已转换为python对象
        """
        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
        # 调用百度api识别文字的参数
        _, buffer = cv2.imencode('.png', image)

        # 使用 base64.b64encode() 将字节数组编码为 Base64 字符串
        img = base64.b64encode(buffer).decode('utf-8')
        params = {"image": img}
        access_token = config["access_token"]
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        # 发送并返回值
        response = requests.post(request_url, data=params, headers=headers)
        time.sleep(0.5)
        if response:
            return response.json()
        else :
            return None

    def ocr_images(self,images):
        """
        所有识别后的json数据
        :param images: opencv image对象列表
        :return: 返回所有图片
        """
        json_results = []
        for image in images:
            json_results.append(self.ocr_image(image))
        return json_results
class Process_image:
    def save_image(self,image, image_type, save_path, image_name):
        """
        保存图片
        :param image:       图片
        :param image_type:  .png
        :param save_path:   保存路径
        :param image_name:  图片名称 i.split(".")[0] + str(rect) + ".png"
        :return:
        """
        cv2.imencode(image_type, image)[1].tofile(os.path.join(save_path, image_name))
    def cv_imread(self, file_path):
        cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
        return cv_img
    def get_rectangle(self, array: np.array):
        x, y, w, h = cv2.boundingRect(array)
        return [x, x + w, y, y + h]
    def get_contours(self, image, if_show=0):
        _image = image.copy()
        if _image is not None:
            lower_blue = np.array([110, 60, 60])
            upper_blue = np.array([115, 255, 255])
            hsv_image = cv2.cvtColor(_image, cv2.COLOR_BGR2HSV)
            blue_mask = cv2.inRange(hsv_image, lower_blue, upper_blue)
            contours, _ = cv2.findContours(blue_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            if if_show:
                cv2.drawContours(_image, contours, -1, (0, 0, 255), 1)
                cv2.imshow("W", _image)
                cv2.waitKey()
            return contours
        else:
            print("图像加载失败")
    def cut_img(self, img, contours, index, min_width=20, min_height=20):
        rect = self.get_rectangle(contours[int(index)])
        if rect[1] - rect[0] > min_width and rect[3] - rect[2] > min_height:
            return img[rect[2]:rect[3], rect[0]:rect[1]], rect
        else:
            return None, None
    def division_image(self, image_path):
        """
        将一个课表中的课程块切开，返回所有image对象
        :param image_path:     图片路径
        :return:images  所有image对象
        """
        images = []
        # 加载图片
        image = self.cv_imread(image_path)
        # 获取轮廓
        contours = self.get_contours(image, 0)
        # 循环截切轮廓
        for j in range(len(contours)):
            image_cut, rect = self.cut_img(image, contours, j)
            if image_cut is not None:
                images.append(image_cut)
        return images

class BaseClassSchedule(Process_image,Process_json_to_txt,Process_txt_to_csv,Ocr_images,SaveCsv):
    pass
class ClassSchedule(BaseClassSchedule):
    """
    对一张课表进行处理
    """
    def __init__(self, class_schedule_path,xlsx_save_path,name):
        self.class_schedule_path = class_schedule_path
        self.name = name
        self.xlsx_save_path = xlsx_save_path
        self.json_data = [] #包含该课表所有的json
        self.txt_data = []
        self.divided_images = []  #元素为image对象，包含切出来的所有对象
        self.csv_data = {}

        self.division_images()
        self.ocr_images()
        self.process_json_txt()
        self.process_txt_csv()
        self.save_csv()

    def division_images(self):
        if self.class_schedule_path :
            self.divided_images = super().division_image(self.class_schedule_path)
        else :
            print("self.class_schedule_path为空")
    def ocr_images(self):
        if self.divided_images :
            self.json_data = super().ocr_images(self.divided_images)
        else :
            print("self.divided_images为空s")
    def process_json_txt(self):
        if self.json_data :
            self.txt_data = super().analyse_json(self.json_data)
        else:
            print("self.json_data为空")
       
    def process_txt_csv(self):
        if self.txt_data :
            self.csv_data = super().process_txt_to_csv(self.txt_data)
        else :
            print("self.txt_data为空")

    def save_csv(self):
        if not self.csv_data :
            print("self.csv_data为空")
        if not self.xlsx_save_path:
            print("self.xlsx_save_path为空")
        if not self.name:
            print("self.name为空")
        super().save_csv(self.csv_data,self.xlsx_save_path,self.name)
ClassSchedule("./课表/xxx上学期.png","./c.xlsx","xxx1")
ClassSchedule("./课表/xxx下学期.png","./c.xlsx","xxx2")





